from Tkinter import Canvas


class Drawable(object):
    def __init__(self, x=0, y=0, **options):
        self.x = x
        self.y = y
        self.options = options
        
    def merge_options(self, extra_options):
        options = self.options
        if len(extra_options) > 0:
            options = dict(self.options)
            options.update(extra_options)
        return options
        
    def draw(self, canvas, x_offset=0, y_offset=0, scale=1.0, **extra_options):
        raise NotImplementedError()
        

class Text(Drawable):
    def __init__(self, text, x=0, y=0, **options):
        Drawable.__init__(self, x, y, **options)
        self.text = str(text)
        
    def draw(self, canvas, x_offset=0, y_offset=0, scale=1.0, **extra_options):
        x = self.x + x_offset
        y = self.y + y_offset
        return canvas.create_text(x * scale, y * scale, text=self.text, 
                                  **self.merge_options(extra_options))
        
        
class RectLike(Drawable):
    draw_fnc = None
    
    def __init__(self, w, h, x=0, y=0, **options):
        Drawable.__init__(self, x, y, **options)
        self.width = w
        self.height = h
        
    def draw(self, canvas, x_offset=0, y_offset=0, scale=1.0, **extra_options):
        x = self.x + x_offset
        y = self.y + y_offset
        left   = x - self.width / 2.0
        right  = left + self.width
        top    = y - self.height / 2.0
        bottom = top + self.height
        return self.draw_fnc(canvas, left * scale, top * scale, 
                             right * scale, bottom * scale, 
                             **self.merge_options(extra_options))
        
        
class Rectangle(RectLike):
    draw_fnc = Canvas.create_rectangle
    
    
class Oval(RectLike):
    draw_fnc = Canvas.create_oval
    

class Triangle(Drawable):
    def __init__(self, w, h, x=0, y=0, facing_up=True, **options):
        Drawable.__init__(self, x, y, **options)
        self.width = w
        self.height = h
        self.facing_up = facing_up
        
    def draw(self, canvas, x_offset=0, y_offset=0, scale=1.0, **extra_options):
        x = self.x + x_offset
        y = self.y + y_offset
        signal = +1 if self.facing_up else -1
        coords = [x - self.width / 2.0, y + signal * self.height / 2.0,
                  x + self.width / 2.0, y + signal * self.height / 2.0,
                  x, y - signal * self.height / 2.0]
        return canvas.create_polygon(*[scale * value for value in coords],
                                     **self.merge_options(extra_options))
        
        
class Line(Drawable):
    def __init__(self, *points, **options):
        Drawable.__init__(self, None, None, **options)
        self.points = list(points)
        
    def draw(self, canvas, x_offset=0, y_offset=0, scale=1.0, **extra_options):
        coords = []
        for x, y in self.points:
            coords.append(scale * (x + x_offset))
            coords.append(scale * (y + y_offset))
        return canvas.create_line(*coords, **self.merge_options(extra_options))
        